//
//  Utils.swift
//  suda
//
//  Created by youai on 2019/7/12.
//  Copyright © 2019年 youi. All rights reserved.
//

import Foundation
//只是为了引入cgfloat
import UIKit
//push 测试

typealias EMPTY_CLOSURE = () -> ()
typealias ENTER_CLOSURE = () -> ()

extension String {
    func trim()->String{
        return trimmingCharacters(in: .whitespacesAndNewlines)
    }
    func afterSubstring(_ substring:String)->String{
        if let range = range(of: substring, options: .caseInsensitive , range: startIndex..<endIndex, locale: nil) {
            return String(self[range.upperBound ..< endIndex ])
        }
        return self
    }
    func beforeSubstring(_ substring:String)->String{
        if let range = range(of: substring, options: [.caseInsensitive , .backwards] , range: startIndex..<endIndex, locale: nil) {
            return String(self[startIndex ..< range.lowerBound ])
        }
        return self
    }
    func _toJSON()->Any?{
        guard let data = data(using: .utf8) else {
            return nil
        }
        return try? JSONSerialization.jsonObject(with: data, options: [])
    }
    
    func toJSONDictionary()->[String:Any?]? {
        return _toJSON() as? [String:Any?]
    }
    
    func toJSONDictList()->[[String:Any?]]? {
        return _toJSON() as? [[String:Any?]]
    }
    
    func urlqueryToDictionary()->[String:Any?] {
        var dic = [String:Any?]()
        let ary = self.components(separatedBy:"&")
        for i in ary {
            let ket_value = i.components(separatedBy:"=")
            if ket_value.count == 2 {
                dic.updateValue(ket_value[1], forKey: ket_value[0])
            }
        }
        return dic
    }
    
    ///如果字符串为空则返回nil，方便用 ?? 符号提供默认值
    var nilIfEmpty : String? {
        if self.isEmpty {
            return nil
        }
        return self
    }
    
    var doubleOrNil : Double? {
        return Double(self)
    }
    var intOrNil : Int? {
        return Int(self)
    }

    var MD5:String {
        let utf8 = cString(using: .utf8)
        var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        CC_MD5(utf8, CC_LONG(utf8!.count - 1), &digest)
        return digest.reduce("") { $0 + String(format:"%02X", $1) }
    }
    
    var md5:String {
        let utf8 = cString(using: .utf8)
        var digest = [UInt8](repeating: 0, count: Int(CC_MD5_DIGEST_LENGTH))
        CC_MD5(utf8, CC_LONG(utf8!.count - 1), &digest)
        return digest.reduce("") { $0 + String(format:"%02x", $1) }
    }
    
    //去掉小数点后面的0
    var quXiaoShuDianHouDeLing : String{
        var outNumber = self
        var i = 1

        if self.contains("."){
            while i < self.count{
                if outNumber.hasSuffix("0") {
                    outNumber.remove(at: outNumber.index(before: outNumber.endIndex))
                    i = i + 1
                } else {
                    break
                }
            }
            if outNumber.hasSuffix("."){
                outNumber.remove(at: outNumber.index(before: outNumber.endIndex))
            }
            return outNumber
        } else {
            return self
        }
    }
}

//判断一些正则表达式
extension String {
    //邮箱
    func validateEmail() -> Bool {
        let emailRegex: String = "[A-Z0-9a-z._%+-]+@[A-Za-z0-9.-]+\\.[A-Za-z]{2,4}"
        let emailTest: NSPredicate = NSPredicate(format: "SELF MATCHES %@", emailRegex)
        return emailTest.evaluate(with: self)
    }
    
    //手机
    func validateMobile() -> Bool {
        if self.count == 11 {
            return true
        }
        return false
//        let phoneRegex: String = "^((13[0-9])|(15[^4,\\D])|(18[0,0-9])|(17[0,0-9]))\\d{8}$"
//        let phoneTest = NSPredicate(format: "SELF MATCHES %@", phoneRegex)
//        return phoneTest.evaluate(with: self)
    }
    
    //密码
    func validatePassword() -> Bool {
        let  passWordRegex = "^(?![0-9]+$)(?![a-zA-Z]+$)[0-9A-Za-z]{8,20}$"
        let passWordPredicate = NSPredicate(format: "SELF MATCHES%@", passWordRegex)
        return passWordPredicate.evaluate(with: self)
    }
    
    //昵称
    func validateNickname() -> Bool {
        let nicknameRegex = "^[\u{4e00}-\u{9fa5}]{4,8}$"
        let passWordPredicate = NSPredicate(format: "SELF MATCHES%@", nicknameRegex)
        return passWordPredicate.evaluate(with: self)
    }
    
    //车牌
    func validateCarNum() -> Bool {
        let carString = "^[A-Za-z]{1}[A-Za-z_0-9]{5}$"
        let carPredicate = NSPredicate(format: "SELF MATCHES %@", carString)
        return carPredicate.evaluate(with: self)
    }
    
    //用户名
    func validateUserName() -> Bool {
        let userNameRegex = "^[A-Za-z0-9]{6,20}+$"
        let userNamePredicate = NSPredicate(format: "SELF MATCHES %@", userNameRegex)
        let peopleName = userNamePredicate.evaluate(with: self)
        return peopleName
    }
}

extension Double {
    func negative()->Double{
        return -self
    }
    

    var clean: String {
        return self.truncatingRemainder(dividingBy: 1) == 0 ? String(format: "%.0f", self) : String(self)
    }
//    //去除多余的小数
//    var round4 : Double {
//        var double4 = self * 10000.0
//        double4.round(.toNearestOrAwayFromZero)
//        return double4 / 10000.0
//    }
    var round0 : Int {
        var double0 = self
        double0.round(.toNearestOrAwayFromZero)
        return Int(double0)
    }
    ///两位小数
    var round2 : Double {
        var double2 = self * 100.0
        double2.round(.toNearestOrAwayFromZero)
        return double2 / 100.0
    }
    ///六位小数
    var round6 : Double {
        var double6 = self * 1000000.0
        double6.round(.toNearestOrAwayFromZero)
        return double6 / 1000000.0
    }
    
    var fix2Str : String{
        return String(format: "%.2f", self)
    }
}

extension Int {
    func double()->Double{
        return Double(self)
    }
    func cgFloat()->CGFloat{
        return CGFloat(self)
    }
    var nilIfMin : Int?{
        if self == Int.min {
            return nil
        }
        return self
    }
}

class WeakReference<T:AnyObject>{
    weak var target : T? = nil
    init(target:T){
        self.target = target
    }
}

extension Dictionary where Key == String {
    var jsonString : String {
        if let desc = try? JSONSerialization.data(withJSONObject: self, options: .prettyPrinted) {
            if let output = NSString(data: desc, encoding: String.Encoding.utf8.rawValue) {
                return output.replacingOccurrences(of: "\\/", with: "/")
            }
        }
        return "[转义失败]" + description
    }
    
    func getInt(_ key : String )->Int?{
        return self[key] as? Int
    }
    
    func getString(_ key : String )->String?{
        return self[key] as? String
    }
    func getDouble(_ key : String )->Double?{
        return self[key] as? Double
    }
    
    func getDictionary(_ key : String )->[String:Any?]?{
        return self[key] as? [String:Any?]
    }
    func getDictList(_ key : String )->[[String:Any?]]?{
        return self[key] as? [[String:Any?]]
    }
    
    func getBool(_ key : String )->Bool?{
        return self[key] as? Bool
    }
}

extension Array{
    func safeGet(idx:Int)->Element?{
        if idx < 0 {
            return nil
        }
        if idx >= count {
            return nil
        }
        return self[idx]
    }
}


extension Date {
    var year : Int {
        let calendar = Calendar.current
        return calendar.component(.year, from: self)
    }
    var month : Int {
        let calendar = Calendar.current
        return calendar.component(.month, from: self)
    }
    var aMonthAgo : Date {
        return Calendar.current.date(byAdding: .month, value: -1, to: self) ?? self.addingTimeInterval(-3600*24*30)
    }
}


struct PropertyAccessor {
    let setter : (Any?)->Void
    let getter : ()->Any?
}

///可以获取访问器的Int属性
class IntProperty {
    var value : Int?
    init(value:Int? = nil){
        self.value = value
    }
    ///获取访问器
    func getAccessor()->PropertyAccessor {
        return PropertyAccessor(setter: { (value) in
            self.value = anyToInt(value)
        }, getter: { () -> Any? in
            return self.value
        })
    }
}

///可以获取访问器的String属性
class StringProperty {
    var value : String?
    init(value : String? = nil){
        self.value = value
    }
    ///获取访问器
    func getAccessor()->PropertyAccessor{
        return PropertyAccessor(setter: { (value) in
            self.value = anyToString(value)
        }, getter: { () -> Any? in
            return self.value
        })
    }
}



///返回主对象的弱引用后闭包（避免[weak self]的写法），无参数
func weakClosure<T:AnyObject>(target:T,closure:@escaping (T)->())->EMPTY_CLOSURE{
    let weakTarget = WeakReference<T>(target: target)
    return {
        if let target = weakTarget.target {
            closure(target)
        }
    }
}

///返回主对象的弱引用后闭包（避免[weak self]的写法），带参数
func weakClosureWithParam<P,T:AnyObject>(target:T,closure:@escaping (P,T)->())->( (P)->() ) {
    let weakTarget = WeakReference<T>(target: target)
    return { param in
        if let target = weakTarget.target {
            closure(param,target)
        }
    }
}

///以某个对象为锁执行过程块
func synchronized<T>(_ lock: AnyObject, _ body: () throws -> T) rethrows -> T {
    objc_sync_enter(lock)
    defer { objc_sync_exit(lock) }
    return try body()
}

func anyToInt(_ value:Any?)->Int?{
    if value == nil { return nil }
    if let origin = value as? Int {
        return origin
    }
    if let str = value as? String {
        return Int(str)
    }
    return nil
}

func anyToDouble(_ value:Any?)->Double?{
    if value == nil { return nil }
    if let origin = value as? Double {
        return origin
    }
    if let str = value as? String {
        return Double(str)
    }
    return nil
}

func anyToString(_ value:Any?)->String?{
    if value == nil { return nil }
    if let intValue = value as? Int {
        return String(describing: intValue)
    }else if let long = value as? Int64 {
        return String(describing: long)
    }else if let doubleValue = value as? Double {
        return String(describing: doubleValue)
    }else if let boolValue = value as? Bool {
        return boolValue ? "true" : "false"
    }
    if let origin = value as? String {
        return origin
    }
    return String(describing: value)
}

func anyToBool(_ value:Any?)->Bool?{
    if value == nil { return nil }
    if let origin = value as? Bool {
        return origin
    }
    if let str = value as? String {
        return Bool(str)
    }
    return false
}

protocol DetailItemProtocol : Equatable {
    var itemno : Int { get }
}

struct DetailListUpdateStruct<T:DetailItemProtocol> {
    ///新增+编辑明细数
    let detail1Count : Int
    ///删除明细数
    let deletedetail1Count : Int
    ///新增+编辑的明细数据
    let detail1 : [T]?
    ///删除的明细数据
    let deletedetail1 : [T]?
    init(detail1Count : Int,deletedetail1Count : Int,detail1 : [T]?,deletedetail1 : [T]?){
        self.detail1Count = detail1Count
        self.deletedetail1Count = deletedetail1Count
        self.detail1 = (detail1?.count ?? 0 == 0) ? nil : detail1
        self.deletedetail1 = (deletedetail1?.count ?? 0 == 0) ? nil : deletedetail1
    }
}

///生成明细数据中删除和新增/编辑数量，以及删除和新增/编辑数组
func DetailListUpdateCount<T:DetailItemProtocol>(originGoodsList : [T], newGoodsList : [T])->DetailListUpdateStruct<T>{
    var removeCount = 0
    var removeList = [T]()
    //如果originGoodsList里的某一项不能在newGoodsList里找到
    originGoodsList.forEach{ o in
        if  (newGoodsList.filter{ n in n.itemno == o.itemno }).first == nil {
            removeCount += 1
            removeList.append(o)
        }
    }
    
    var appendAndModifyCount = 0
    var appendAndModify = [T]()
    //如果newGoodsList里的某一项不能在oldGoodsList里找到
    //或者能找到，但两者的值不一致
    newGoodsList.forEach{ n in
        var exists = false
        for o in originGoodsList {
            if o.itemno == n.itemno {
                exists = true
                if o != n {
                    appendAndModifyCount += 1
                    appendAndModify.append(n)
                }
            }
        }
        if !exists {
            appendAndModifyCount += 1
            appendAndModify.append(n)
        }
    }
    return DetailListUpdateStruct<T>(detail1Count: appendAndModifyCount,
                                    deletedetail1Count: removeCount,
                                    detail1: appendAndModify,
                                    deletedetail1: removeList)
}
